#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <limits.h>
#include <inttypes.h>

#define SCRAMBLE_LENGTH 20

__attribute__((weak))
char** setlist (int leng)
{
    char **array = NULL;
    printf("setlist sizeof(*array)=%d", sizeof(char *));
    array = (char**)malloc(leng*sizeof(char *)); //修改微char *
    printf("setlist sizeof(array)=%d", sizeof(char *));
    return array;

}

__attribute__((weak))
char** setlistvalue (char **array, int index, char *data)
{
    array[index] = data;
    return array;
}


struct DbInfo{
    char* server;
    char* user;
    char* pwd;
    char* db;
    int port;
};

struct ResultInfo{
    char* strId;
    char* ers;
};

struct ResultArrayInfo{
    char **strArr;
    char* ers;
    int leng;
};

struct TControlCenter{
   int Id;
   int Xid;
   int DType;
   int Tid;
};

typedef struct SqlHost {
   int Id;
   char* Name;               // 主机别名
   char* Host; // 数据库服务器名称
   int  Port;                // 主机端口
   char*   Remark; // 备注
   int Databasetype;
   char*  User;
   char*  Password;
   char*  Database;
   char*  Charset;
   char*  Locate;// 备份位置
   char*  Version;
   char*  Sqlpath;
   int    Local;
   int    Wmode;
   char*   ResOne;
   char*   ResTwo;
   char*   ResThree;
   char*    ResFour;
   int    IdOne;
   int    IdTwo;
   int    IdThree;
   int    IdFour;
}SqlHost;

typedef struct ResultArraySQLInfo {
    SqlHost** sqlhosts;
    char* ers;
    int leng;
}ResultArraySQLInfo;


__attribute__((weak))
SqlHost** setsqlarray (int leng)
{
    SqlHost** array = NULL;
    printf("setlist sizeof(*array)=%d", sizeof(SqlHost *));
    array = (SqlHost**)malloc(leng*sizeof(SqlHost *)); //修改微char *
    printf("setlist sizeof(array)=%d", sizeof(SqlHost *));
    return array;
}

__attribute__((weak))
SqlHost** setarrayvalue (SqlHost** array, int index, SqlHost *data)
{
    array[index] = data;
    return array;
}

enum enum_field_types {
  MYSQL_TYPE_DECIMAL,
  MYSQL_TYPE_TINY,
  MYSQL_TYPE_SHORT,
  MYSQL_TYPE_LONG,
  MYSQL_TYPE_FLOAT,
  MYSQL_TYPE_DOUBLE,
  MYSQL_TYPE_NULL,
  MYSQL_TYPE_TIMESTAMP,
  MYSQL_TYPE_LONGLONG,
  MYSQL_TYPE_INT24,
  MYSQL_TYPE_DATE,
  MYSQL_TYPE_TIME,
  MYSQL_TYPE_DATETIME,
  MYSQL_TYPE_YEAR,
  MYSQL_TYPE_NEWDATE, /**< Internal to MySQL. Not used in protocol */
  MYSQL_TYPE_VARCHAR,
  MYSQL_TYPE_BIT,
  MYSQL_TYPE_TIMESTAMP2,
  MYSQL_TYPE_DATETIME2,   /**< Internal to MySQL. Not used in protocol */
  MYSQL_TYPE_TIME2,       /**< Internal to MySQL. Not used in protocol */
  MYSQL_TYPE_TYPED_ARRAY, /**< Used for replication only */
  MYSQL_TYPE_INVALID = 243,
  MYSQL_TYPE_BOOL = 244, /**< Currently just a placeholder */
  MYSQL_TYPE_JSON = 245,
  MYSQL_TYPE_NEWDECIMAL = 246,
  MYSQL_TYPE_ENUM = 247,
  MYSQL_TYPE_SET = 248,
  MYSQL_TYPE_TINY_BLOB = 249,
  MYSQL_TYPE_MEDIUM_BLOB = 250,
  MYSQL_TYPE_LONG_BLOB = 251,
  MYSQL_TYPE_BLOB = 252,
  MYSQL_TYPE_VAR_STRING = 253,
  MYSQL_TYPE_STRING = 254,
  MYSQL_TYPE_GEOMETRY = 255
};

typedef struct MYSQL_FIELD {
  char *name;               /* Name of column */
  char *org_name;           /* Original column name, if an alias */
  char *table;              /* Table of column if column was a field */
  char *org_table;          /* Org table name, if table was an alias */
  char *db;                 /* Database for table */
  char *catalog;            /* Catalog for table */
  char *def;                /* Default value (set by mysql_list_fields) */
  unsigned long length;     /* Width of column (create length) */
  unsigned long max_length; /* Max width for selected set */
  unsigned int name_length;
  unsigned int org_name_length;
  unsigned int table_length;
  unsigned int org_table_length;
  unsigned int db_length;
  unsigned int catalog_length;
  unsigned int def_length;
  unsigned int flags;         /* Div flags */
  unsigned int decimals;      /* Number of decimals in field */
  unsigned int charsetnr;     /* Character set */
  unsigned int type; /* Type of field. See mysql_com.h for types */
  unsigned long precision;  //DecimalSize()
  unsigned long scale;      //DecimalSize()
//  void *extension;
} MYSQL_FIELD;


typedef char **MYSQL_ROW;                /* return data as array of strings */
typedef unsigned int MYSQL_FIELD_OFFSET; /* offset to current field */
typedef unsigned long ulong;
typedef unsigned int uint;

/** Max length of a error message. Should be kept in sync with ::ERRMSGSIZE. */
#define MYSQL_ERRMSG_SIZE 512
/* Server error code and message */
unsigned int mysql_server_last_errno __attribute__((weak));
char* mysql_server_last_error __attribute__((weak));
unsigned int mysql_port __attribute__((weak))= 0;
char *mysql_unix_port __attribute__((weak))= NULL;
char *unknown_sqlstate __attribute__((weak))= "HY000";
const char *not_error_sqlstate __attribute__((weak))= "00000";
const char *cant_connect_sqlstate __attribute__((weak))= "08001";

typedef struct MYSQL_ROWS {
  struct MYSQL_ROWS *next; /* list of rows */
  MYSQL_ROW data;
  unsigned long length;
} MYSQL_ROWS;

typedef MYSQL_ROWS *MYSQL_ROW_OFFSET; /* offset to current row */

enum enum_resultset_metadata {
  /** No metadata will be sent. */
  RESULTSET_METADATA_NONE = 0,
  /** The server will send all metadata. */
  RESULTSET_METADATA_FULL = 1
};


typedef struct MYSQL_DATA {
  MYSQL_ROWS *data;
//  struct MEM_ROOT *alloc;
  uint64_t rows;
  uint32_t fields;
} MYSQL_DATA;

typedef struct NET {
//  MYSQL_VIO vio;
  unsigned char *buff, *buff_end, *write_pos, *read_pos;
//  my_socket fd; /* For Perl DBI/dbd */
  /**
    Set if we are doing several queries in one
    command ( as in LOAD TABLE ... FROM MASTER ),
    and do not want to confuse the client with OK at the wrong time
  */
  uint64_t remain_in_buf, length, buf_length, where_b; //unsigned long
  uint64_t max_packet, max_packet_size;
  uint32_t pkt_nr, compress_pkt_nr;
  uint32_t write_timeout, read_timeout, retry_count;
  int32_t fcntl;
  uint32_t *return_status;
  unsigned char reading_or_writing;
  unsigned char save_char;
  _Bool compress;
  uint32_t last_errno; //unsigned int
  unsigned char error;
  /** Client library error message buffer. Actually belongs to struct MYSQL. */
  char* last_error;   //last_error[MYSQL_ERRMSG_SIZE];
  /** Client library sqlstate buffer. Set along with the error message. */
  char* sqlstate;   //sqlstate[SQLSTATE_LENGTH + 1];
  /**
    Extension pointer, for the caller private use.
    Any program linking with the networking library can use this pointer,
    which is handy when private connection specific data needs to be
    maintained.
    The mysqld server process uses this pointer internally,
    to maintain the server internal instrumentation for the connection.
  */
//  void *extension;
} NET;

typedef struct MYSQL {
  NET net;                     /* Communication parameters */
  unsigned char *connector_fd; /* ConnectorFd for SSL */
  uint64_t connectID;
  uint64_t rowsID;
  char *host, *user, *passwd, *unix_socket, *server_version, *host_info;
  char *info, *db;
//  struct CHARSET_INFO *charset;
  MYSQL_FIELD *fields;
//  struct MEM_ROOT *field_alloc;
  uint64_t affected_rows;
  uint64_t insert_id;      /* id if insert on table with NEXTNR */
  uint64_t extra_info;     /* Not used */
  uint64_t thread_id; /* Id for connection in server unsigned long */
  uint64_t packet_length; //unsigned long
  uint32_t port;
  uint64_t client_flag, server_capabilities;
  uint32_t protocol_version;
  uint32_t field_count;
  uint32_t server_status;
  uint32_t server_language;
  uint32_t warning_count;

//  struct st_mysql_options options;
  _Bool status;
//  enum enum_resultset_metadata resultset_metadata;
  _Bool free_me;   /* If free in mysql_close */
  _Bool reconnect; /* set to 1 if automatic reconnect */

  /* session-wide random string */
  char scramble[SCRAMBLE_LENGTH + 1];

//  LIST *stmts; /* list of all statements */
//  const struct MYSQL_METHODS *methods;
  void *thd;
  /*
    Points to boolean flag in MYSQL_RES  or MYSQL_STMT. We set this flag
    from mysql_stmt_close if close had to cancel result set of this object.
  */
  _Bool *unbuffered_fetch_owner;
//  void *extension;
} MYSQL;

typedef struct MYSQL_RES {
  uint64_t row_count;
  MYSQL_FIELD *fields;
  struct MYSQL_DATA *data;
  MYSQL_ROWS *data_cursor;
  unsigned long *lengths; /* column lengths of current row */
  //MYSQL *handle;          /* for unbuffered reads */
  //const struct MYSQL_METHODS *methods;
  MYSQL_ROW row;         /* If unbuffered read */
  MYSQL_ROW current_row; /* buffer to current row */
//  struct MEM_ROOT *field_alloc;
  unsigned int field_count, current_field;
  _Bool eof; /* Used by mysql_fetch_row */
  /* mysql_stmt_close() had to cancel this result */
  _Bool unbuffered_fetch_cancelled;
  unsigned int metadata;   //enum enum_resultset_metadata metadata;
  //void *extension;
} MYSQL_RES;


__attribute__((weak))
MYSQL_RES * setMemMYSQLRES (int leng)
{
    return  (MYSQL_RES *)malloc(sizeof(MYSQL_RES) + sizeof(ulong)*leng);
}

__attribute__((weak))
MYSQL_DATA * setMemMYSQLDATA ()
{
    return  (MYSQL_DATA *)malloc(sizeof(MYSQL_DATA));
}

__attribute__((weak))
MYSQL_ROWS * setMemMYSQL_ROWS ()
{
    return  (MYSQL_ROWS *)malloc(sizeof(MYSQL_ROWS));
}

__attribute__((weak))
MYSQL_ROW setMemMYSQL_ROW (int leng)
{
    return  (MYSQL_ROW)malloc((leng + 1)*sizeof(char *)); //+ 1难道最后一个是空
}

__attribute__((weak))
MYSQL_ROWS* setROWSvalue (MYSQL_ROWS* ret, int index, char *data)
{
     ret->data[index] = data;
     return ret;
}

__attribute__((weak))
void  mysql_data_seek(MYSQL_RES *result, uint64_t row) {
  MYSQL_ROWS *tmp = NULL;
  if (result->data)
    for (tmp = result->data->data; row-- && tmp; tmp = tmp->next);
  result->current_row = NULL;
  result->data_cursor = tmp;
}

__attribute__((weak))
MYSQL_ROW  mysql_fetch_row(MYSQL_RES *res) {
  MYSQL_ROW tmp;
  if (!res->data_cursor) {
  // DBUG_PRINT("info", ("end of data"));
     return res->current_row = (MYSQL_ROW) NULL;
   }
   tmp = res->data_cursor->data;
   res->data_cursor = res->data_cursor->next;
   return res->current_row = tmp;
}

__attribute__((weak))
MYSQL_FIELD* setMemMYSQL_FIELD (int leng)
{
    MYSQL_FIELD* result;
    result =  (MYSQL_FIELD *)malloc(sizeof(MYSQL_FIELD) * leng);
    return memset(result, 0, sizeof(MYSQL_FIELD) * leng);  //初始化
}

__attribute__((weak))
void MYSQL_FIELD_inc (MYSQL_FIELD* field)
{
  field++;
}

__attribute__((weak))
void setdberror(MYSQL *mysql,  char *last_error ,  char *sqlstate) {
  NET *net;
//  DBUG_TRACE;
//  DBUG_PRINT("enter", ("error :%d '%s'", errcode, ER_CLIENT(errcode)));
//  assert(mysql != nullptr);

  if (mysql) {
    net = &mysql->net;
//    net->last_errno = errcode;

   // my_stpmov(net->last_error, ER_CLIENT(errcode));
    //my_stpmov(net->sqlstate, sqlstate);
    net->last_error = last_error;
    net->sqlstate = sqlstate;

  } else {
//    mysql_server_last_errno = errcode;
    mysql_server_last_error = last_error;
//    my_stpcpy(mysql_server_last_error, ER_CLIENT(errcode));
  }
}


__attribute__((weak))
MYSQL * mysql_init(MYSQL *mysql)
{
  if (!mysql) {
    if (!(mysql = (MYSQL *)malloc(sizeof(*mysql)))) {
      setdberror(NULL, "CR_OUT_OF_MEMORY", unknown_sqlstate);
      return NULL;
    }
    mysql->free_me = true;
  } else
    memset(mysql, 0, sizeof(*(mysql)));
  return mysql;
}

/* MYSQL_RES */
__attribute__((weak))
uint64_t mysql_num_rows(MYSQL_RES *res) {
  return res->row_count;
}

__attribute__((weak))
uint32_t mysql_num_fields(MYSQL_RES *res) {
  return res->field_count;
}

__attribute__((weak))
uint32_t mysql_errno(MYSQL *mysql) {   //uint = unsigned int
  return mysql ? mysql->net.last_errno : mysql_server_last_errno;
}

__attribute__((weak))
char * mysql_error(MYSQL *mysql) {
  return mysql ? mysql->net.last_error : mysql_server_last_error;
}

__attribute__((weak))
void free_rows(MYSQL_ROWS* head) {
    MYSQL_ROWS* current = head;
    MYSQL_ROWS* next = NULL;

    while (current != NULL) {
        next = current->next;  // 保存下一个节点的地址
        free(current);         // 释放当前节点
        current = next;        // 移动到下一个节点
    }
}

__attribute__((weak))
void mysql_free_result(MYSQL_RES *res){
    if (res) {
      free_rows(res->data->data); //rows free;
      free(res->data);
      free(res->fields);
      free(res);
    }
}

//__attribute__((weak))
//static inline char *my_stpmov(char *dst, const char *src) {
//  while ((*dst++ = *src++)) {
//  }
//  return dst - 1;
//}






